#include "Direct3DFramework.h"

int Direct3DFramework::createEffect(DEffect* a_effect, char* a_path)
{
	//check if effect already exists
	for(int i = 0; i < m_effectList.size(); i++)
	{
		if(a_path == m_effectList[i]->m_path)
		{
			D3DFEffect* effect = m_effectList[i];
			a_effect->m_effId   = effect->m_id;
			a_effect->m_effPath = effect->m_path;

			//return after completion
			return D3D_SUCCESS;
		}
	}

	//create new effect
	D3DFEffect* effect = new D3DFEffect;

	//load effect from file
	D3DXCreateEffectFromFile(
		m_device,a_path,0,0,0,0,
		&effect->m_effect,0);

	//init effect
	effect->init();

	//fill effect struct
	effect->m_id = m_effectList.size();
	effect->m_path = a_path;

	a_effect->m_effId = effect->m_id;
	a_effect->m_effPath = effect->m_path;

	//add to effect list
	m_effectList.insertBack(effect);

	//return after completion
	return D3D_SUCCESS;
}

int Direct3DFramework::createTexture2D(DTexture2D* a_texture, int a_width, int a_height, int a_format)
{
	D3DFORMAT format = D3DFMT_UNKNOWN;
	switch(a_format)
	{
	case D3D_SURF_XRGB: format = D3DFMT_A8R8G8B8; break;
	case D3D_SURF_ARGB: format = D3DFMT_X8R8G8B8; break;
	case D3D_SURF_R16F: format = D3DFMT_R16F; break;
	case D3D_SURF_R32F: format = D3DFMT_R32F; break;
	};

	D3DFTexture2D* texture = new D3DFTexture2D;
	m_device->CreateTexture(
		a_width,a_height,1,
		D3DUSAGE_RENDERTARGET,
		format,D3DPOOL_DEFAULT,
		&texture->m_texture,0);

	texture->m_id = m_texture2DList.size();
	a_texture->m_texId = texture->m_id;

	m_texture2DList.insertBack(texture);

	//return after completion
	return D3D_SUCCESS;
}

int Direct3DFramework::createTexture2D(DTexture2D* a_texture, char* a_path)
{
	//check if texture exist
	for(int i = 0; i < m_texture2DList.size(); i++)
	{
		D3DFTexture2D* texture = m_texture2DList.get(i);
		if(!strcmp(a_path,texture->m_path))
		{
			//set texture info
			a_texture->m_texId		= texture->m_id;
			a_texture->m_texPath	= texture->m_path;
			a_texture->m_texWidth	= texture->m_info.Width;
			a_texture->m_texHeight	= texture->m_info.Height;
			a_texture->m_texMat     = texture->m_world.size();
			texture->m_world.insertBack(D3DFMat2D());
			return D3D_SUCCESS;
		}
	}

	//create texture
	D3DFTexture2D* texture = new D3DFTexture2D;
	D3DXCreateTextureFromFileEx(
		m_device,
		TEXT(a_path),
		D3DX_DEFAULT_NONPOW2,
		D3DX_DEFAULT_NONPOW2,
		0,0,
		D3DFMT_UNKNOWN,
		D3DPOOL_MANAGED,
		D3DX_DEFAULT,
		D3DX_DEFAULT,
		D3DCOLOR_XRGB(255,0,255),
		&texture->m_info,0,
		&texture->m_texture);

	//set texture info
	texture->m_id	= m_texture2DList.size();
	strcpy_s(texture->m_path,128,a_path);

	a_texture->m_texId     = texture->m_id;
	a_texture->m_texPath   = texture->m_path;
	a_texture->m_texWidth  = texture->m_info.Width;
	a_texture->m_texHeight = texture->m_info.Height;
	a_texture->m_texMat    = texture->m_world.size();
	texture->m_world.insertBack(D3DFMat2D());

	//add texture to texture list
	m_texture2DList.insertBack(texture);

	//return after completion
	return D3D_SUCCESS;
}

int Direct3DFramework::createTexture3D(DTexture3D* a_texture, char* a_path)
{
	//check if texture exist
	for(int i = 0; i < m_texture3DList.size(); i++)
	{
		D3DFTexture3D* texture = m_texture3DList.get(i);
		if(!strcmp(a_path,texture->m_path))
		{
			//set texture info
			a_texture->m_texId		= texture->m_id;
			a_texture->m_texPath	= texture->m_path;
			a_texture->m_texWidth	= texture->m_info.Width;
			a_texture->m_texHeight	= texture->m_info.Height;
			return D3D_SUCCESS;
		}
	}

	//create texture
	D3DFTexture3D* texture = new D3DFTexture3D;
	D3DXCreateCubeTextureFromFileEx(
		m_device,
		TEXT(a_path),
		D3DX_DEFAULT,
		D3DX_DEFAULT,0,
		D3DFMT_UNKNOWN,
		D3DPOOL_MANAGED,
		D3DX_DEFAULT,
		D3DX_DEFAULT,
		D3DCOLOR_XRGB(255,0,255),
		&texture->m_info,0,
		&texture->m_texture);

	//set texture info
	texture->m_id	= m_texture3DList.size();
	strcpy_s(texture->m_path,128,a_path);

	a_texture->m_texId     = texture->m_id;
	a_texture->m_texPath   = texture->m_path;
	a_texture->m_texWidth  = texture->m_info.Width;
	a_texture->m_texHeight = texture->m_info.Height;

	//add texture to texture list
	m_texture3DList.insertBack(texture);

	//return after completion
	return D3D_SUCCESS;
}

int Direct3DFramework::createMesh(DMesh* a_mesh, char* a_path)
{
	//check if mesh already exists
	for(int i = 0; i < m_meshList.size(); i++)
	{
		if(!strcmp(a_path,m_meshList[i]->m_path))
		{
			D3DFMesh* mesh = m_meshList[i];
			a_mesh->m_meshId   = mesh->m_id;
			a_mesh->m_meshPath = mesh->m_path;
			a_mesh->m_meshMat  = mesh->m_world.size();
			mesh->m_world.insertBack(D3DXMATRIX());
			D3DXMatrixIdentity(&mesh->m_world[a_mesh->m_meshMat]);

			//return after completion
			return D3D_SUCCESS;
		}
	}

	//create new mesh
	D3DFMesh* mesh = new D3DFMesh;

	//temp variables
	DWORD matAmount = 0;
	ID3DXMesh* loadMesh = 0;
	ID3DXMesh* clonMesh = 0;
	ID3DXMesh* optiMesh = 0;
	ID3DXBuffer* adjBuffer = 0;
	ID3DXBuffer* matBuffer = 0;

	//load mesh from file
	D3DXLoadMeshFromX(
		a_path,
		D3DXMESH_SYSTEMMEM,
		m_device,
		&adjBuffer,
		&matBuffer,0,
		&matAmount,
		&loadMesh);

	//change mesh vertex format to defined vertex format
	unsigned int amount;
	D3DVERTEXELEMENT9 elements[64];
	m_vertDeclMesh->GetDeclaration(elements,&amount);

	loadMesh->CloneMesh(
		D3DXMESH_SYSTEMMEM,
		elements,
		m_device,
		&clonMesh);
	D3DF_RELEASE_URN(loadMesh);

	//compute binormal and tangent
	D3DXComputeTangent(clonMesh,0,0,0,1,0);

	//optimize mesh
	clonMesh->Optimize(
		D3DXMESH_MANAGED | 
		D3DXMESHOPT_COMPACT |
		D3DXMESHOPT_ATTRSORT |
		D3DXMESHOPT_VERTEXCACHE,
		(DWORD*)adjBuffer->GetBufferPointer(),
		0,0,0,&optiMesh);
	D3DF_RELEASE_URN(clonMesh);

	//fill the mesh struct
	mesh->m_id = m_meshList.size();
	strcpy_s(mesh->m_path,128,a_path);
	mesh->m_subs = matAmount;
	mesh->m_mesh = optiMesh;

	//create linked textures from mesh
	if(matBuffer != 0 && matAmount != 0)
	{
		D3DXMATERIAL* material = (D3DXMATERIAL*)matBuffer->GetBufferPointer();

		for(unsigned int i = 0; i < matAmount; i++)
		{
			char* texPath = material[i].pTextureFilename;
			if(texPath != 0)
			{
				char path[256];
				for(int i=0;i<256;i++) path[i]=0;
				strcpy_s(path,"textures/");
				strcat_s(path,texPath);

				DTexture2D texture;
				createTexture2D(&texture,path);
				mesh->m_texs.insertBack(texture.m_texId);
			}
			else
			{
				mesh->m_texs.insertBack(-1);
			}
		}
	}

	//fill the extern mesh struct
	a_mesh->m_meshId = mesh->m_id;
	a_mesh->m_meshPath = mesh->m_path;
	a_mesh->m_meshMat  = mesh->m_world.size();
	mesh->m_world.insertBack(D3DXMATRIX());
	D3DXMatrixIdentity(&mesh->m_world[a_mesh->m_meshMat]);

	//add it to mesh list
	m_meshList.insertBack(mesh);

	//return after completion
	return D3D_SUCCESS;
}

int Direct3DFramework::createSurface(DSurface* a_surface, int a_type)
{
	//return after completion
	return D3D_SUCCESS;
}

int Direct3DFramework::createSurface(DSurface* a_surface, DTexture2D* a_texture)
{
	D3DFSurface* surface = new D3DFSurface;
	D3DFTexture2D* texture = m_texture2DList[a_texture->m_texId];

	texture->m_texture->GetSurfaceLevel(0,&surface->m_surface);

	surface->m_id = m_surfaceList.size();
	surface->m_type = D3D_SURF_TEXTURE;

	a_surface->m_surfId = surface->m_id;
	a_surface->m_surfType = surface->m_type;

	m_surfaceList.insertBack(surface);

	//return after completion
	return D3D_SUCCESS;
}